#coding:utf-8
"""
IP数据包头结构,RFC791,20byte
 0                   1                   2                   3   
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
TCP数据包头,RFC793,20byte
 0                   1                   2                   3   
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |           |U|A|P|R|S|F|                               |
| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
|       |           |G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

TODO:
1.只能修改TCP头，还不能修改IP头
2.windows平台不能使用
"""

import socket
import sys
import struct
import random
import binascii
import time
from time import sleep
import threading
from Queue import Queue

if len(sys.argv) < 2:
	print 'version 0.1'
	print "%s [count] [ip or domain]" % sys.argv[0]
	print "%s www.xxx.com" % sys.argv[0]
	sys.exit(1)
	
	
	
#校验函数,计算校验值
def checksum(msg):
	s = 0
	#
	for i in range(0, len(msg), 2):
		w = (ord(msg[i]) << 8) + (ord(msg[i+1]))
		s = s + w
		
	s = (s >> 16) + (s & 0xffff);
	#s = s + (s >> 16); 
	#补充和掩盖4字节的short
	s = ~s & 0xffff
	
	return s
	
DEST_IP = sys.argv[1]
	
#压力测试参数
THREAD_NUM = 5			# 并发线程总数
ONE_WORKER_NUM = 1		# 每个线程的循环次数
LOOP_SLEEP = 0.5		# 每次请求时间间隔(秒)

# 出错数
ERROR_NUM = 0

#构建封包
packet = ''
#源IP和目的IP
source_ip = socket.gethostbyname(socket.gethostname()) #'192.168.1.102' 
dest_ip = DEST_IP #socket.gethostbyname(DEST_IP)

def do_syn_one(ip):
	#构建TCP头
	source_port = random.randint(1024, 65000)
	dest_port = 80
	seq = socket.htonl(int(time.time()))
	ack_seq = 0
	doff = 5
	offset_res = (doff << 4) + 0  #80
	#TCP标志位
	fin = 0
	syn = 1
	rst = 0
	psh = 0
	ack = 0
	urg = 0
	tcp_flags = fin + (syn << 1) + (rst << 2) + (psh << 3) + (ack << 4) + (urg << 5)  #2
	windows = socket.htons(65535)
	check = 0
	urg_ptr = 0
	#完整的tcp头,没有正确的checksum
	tcp_header = struct.pack("!HHLLBBHHH", source_port, dest_port, seq, ack_seq, offset_res, tcp_flags, windows, check, urg_ptr)
	#构建伪报头字段
	#source_ip = "192.168.1.102"
	#dest_ip = "192.168.1.100"
	source_address = socket.inet_aton( source_ip )
	dest_address = socket.inet_aton( dest_ip )
	placeholder = 0
	protocol = socket.IPPROTO_TCP
	tcp_length = len(tcp_header)
	#伪报头
	psh_tcp_header = struct.pack("!4s4sBBH", source_address, dest_address, placeholder, protocol, tcp_length)
	psh_tcp_header = psh_tcp_header + tcp_header
	#计算正确的checksum
	tcp_check = checksum(psh_tcp_header)
	#重新构造TCP报头，填写正确的校验值
	tcp_header = struct.pack("!HHLLBBH", source_port, dest_port, seq, ack_seq, offset_res, tcp_flags, windows) + struct.pack("H", tcp_check) + struct.pack("!H", urg_ptr)
	print binascii.hexlify(tcp_header)

	#创建一个raw socket
	try:
		s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)  #IPPROTO_TCP,socket.IPPROTO_RAW)
	except socket.error , msg:
		print 'Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
		sys.exit()

	packet = tcp_header
	s.sendto(packet, (ip, 0))

#def do_one(ip):
	#s.sendto(packet, (ip, 0))

def working():
	i = 0
	while i < ONE_WORKER_NUM:
		#s.sendto(packet, (dest_ip, 0))
		do_syn_one(dest_ip)
#		print binascii.hexlify(packet)
		i = i + 1
		sleep(LOOP_SLEEP)

if __name__ == '__main__':
	working()
